package cn.sdormitory.exam.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.sdormitory.basedata.dao.BStudentDao;
import cn.sdormitory.basedata.entity.BStudent;
import cn.sdormitory.common.utils.SysUserUtils;
import cn.sdormitory.exam.dao.ExamInfoDao;
import cn.sdormitory.exam.dao.ExamResultInfoDao;
import cn.sdormitory.exam.service.ExamInfoService;
import cn.sdormitory.exam.service.ExamResultInfoService;
import cn.sdormitory.exam.vo.ExamInfoVO;
import cn.sdormitory.exam.vo.ExamResultInfoVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ExamResultInfoServiceImpl extends ServiceImpl<ExamResultInfoDao, ExamResultInfoVO> implements ExamResultInfoService {
	
	@Resource
	private ExamInfoDao examInfoDao;
	
	@Resource
	private BStudentDao bStudentDao;
	
	@Resource
	private ExamResultInfoDao examResultInfoDao;
	
	@Resource
	private ExamInfoService examInfoService;
	
	@Override
	public IPage<ExamResultInfoVO> findExamResultPageList(ExamResultInfoVO vo) {
		if (Objects.isNull(vo.getExamRecord())) vo.setExamRecord(0);
		int count = examResultInfoDao.findExamResultPageListCount(vo);
		int startNum = (vo.getPageNum() - 1) * vo.getPageSize();
		vo.setPageNum(startNum);
		List<ExamResultInfoVO> examInfoList = examResultInfoDao.findExamResultPageList(vo);
		IPage<ExamResultInfoVO> page = new Page<>();
		page.setTotal(count);
		page.setRecords(examInfoList);
		return page;
	}
	
	@Override
	@Transactional
	public int addOrUpdateExamResult(ExamResultInfoVO vo) {
		if (vo.getExamRecord() > 0) {
			// 录入补考成绩
			ExamInfoVO infoVO = insertExamInfo(vo);
			if (Objects.isNull(infoVO)) {
				// 插入考试信息失败
				return -1;
			}
			
			insertExamStudents(vo, infoVO);
			return 1;
		}
		if (Objects.isNull(vo.getId())) {
			// 新增考试信息
			// 先插入考试信息 返回插入的考试信息数据
			ExamInfoVO infoVO = insertExamInfo(vo);
			if (Objects.isNull(infoVO)) {
				// 插入考试信息失败
				return -1;
			}
			
			insertExamStudents(vo, infoVO);
			return 1;
		}
		
		// 修改考试信息 1.先更新考试信息表，2.更新考试结果表
		Integer x = updateExamInfoAndResult(vo);
		if (x != null) return x;
		return 0;
/*        int num = 0;
        if (StringUtils.isEmpty(vo.getId())){
            // 查询考试结果表是第几次补考成绩的录入
            int examRecord = baseMapper.findExamRecord(infoVO.getId(), vo.getClassId());
            //查看考试是否有成绩录入
            LambdaQueryWrapper<ExamResultInfoVO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ExamResultInfoVO::getExamId,infoVO.getId());
            wrapper.eq(ExamResultInfoVO::getExamRecord, Objects.isNull(examRecord) ? 0 : examRecord + 1);
            wrapper.and((queryWrapper) -> {
                queryWrapper.eq(ExamResultInfoVO::getClassId, vo.getClassId());
            });
            int count = this.baseMapper.selectCount(wrapper);
            if(count>0) return -1;
           
            
            List<Map<String,Object>> examResultMap =  vo.getExamStudents();
            ExamResultInfoVO saveVo = null;
            for (Map<String,Object> map : examResultMap){
                saveVo = new ExamResultInfoVO();
                saveVo.setExamId(String.valueOf(infoVO.getId()));
                saveVo.setIsPass(map.get("isPass")+"");
                saveVo.setClassId(vo.getClassId());
                saveVo.setStudentNo(map.get("studentNo")+"");
                saveVo.setStudentName(map.get("studentName")+"");
                saveVo.setClassName(vo.getClassName());
                saveVo.setCreateBy(username);
                saveVo.setCreateTime(new Date());
                saveVo.setExamRecord(Objects.isNull(examRecord) ? 0 : examRecord + 1);
                this.baseMapper.insert(saveVo);
                num++;
            }
        }else{
            //删除原有结果，再做新增
            LambdaQueryWrapper<ExamResultInfoVO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ExamResultInfoVO::getExamId,infoVO.getId());
            this.baseMapper.delete(wrapper);
            List<Map<String,Object>> examResultMap =  vo.getExamStudents();
            ExamResultInfoVO saveVo = null;
            for (Map<String,Object> map : examResultMap){
                saveVo = new ExamResultInfoVO();
                saveVo.setExamId(String.valueOf(infoVO.getId()));
                saveVo.setIsPass(map.get("isPass")+"");
                saveVo.setClassId(vo.getClassId());
                saveVo.setStudentNo(map.get("studentNo")+"");
                saveVo.setStudentName(map.get("studentName")+"");
                saveVo.setClassName(vo.getClassName());
                saveVo.setCreateBy(username);
                saveVo.setExamRecord(vo.getExamRecord());
                saveVo.setCreateTime(new Date());
                this.baseMapper.insert(saveVo);
                num++;
            }
        }
        return num;*/
	}
	
	private boolean insertExamStudents(ExamResultInfoVO vo, ExamInfoVO infoVO) {
		// 再插入学生成绩信息
		String username = SysUserUtils.getSysUser().getUsername();
		
		// 新增学生成绩
		List<Map<String, Object>> examStudents = vo.getExamStudents();
		List<ExamResultInfoVO> resultInfoVOS = new ArrayList<>();
		for (Map<String, Object> map : examStudents) {
			ExamResultInfoVO saveVo = new ExamResultInfoVO();
			saveVo.setExamId(String.valueOf(infoVO.getId()));
			if (vo.getExamRecord() > 0 ) {
				saveVo.setExamId(String.valueOf(vo.getId()));
				saveVo.setResitExamId(infoVO.getId());
			}
			saveVo.setIsPass(map.get("isPass") + "");
			saveVo.setClassId(vo.getClassId());
			saveVo.setStudentNo(map.get("studentNo") + "");
			saveVo.setStudentName(map.get("studentName") + "");
			saveVo.setClassName(vo.getClassName());
			saveVo.setCreateBy(username);
			saveVo.setCreateTime(new Date());
			saveVo.setExamRecord(vo.getExamRecord());
			resultInfoVOS.add(saveVo);
		}
		return saveBatch(resultInfoVOS);
	}
	
	@Nullable
	private Integer updateExamInfoAndResult(ExamResultInfoVO vo) {
		updateExamInfo(vo);
		
		List<ExamResultInfoVO> resultInfoVOS = new ArrayList<>();
		List<Map<String, Object>> examStudents = vo.getExamStudents();
		for (Map<String, Object> map : examStudents) {
			ExamResultInfoVO resultVo = new ExamResultInfoVO();
			resultVo.setId(Long.valueOf(String.valueOf(map.get("id"))));
			resultVo.setExamId(String.valueOf(map.get("examId")));
			resultVo.setIsPass(String.valueOf(map.get("isPass")));
			resultVo.setScore(String.valueOf(map.get("score")));
			resultVo.setClassId(String.valueOf(vo.getClassId()));
			resultVo.setStudentNo(String.valueOf(map.get("studentNo")));
			resultVo.setStudentName(String.valueOf(map.get("studentName")));
			resultVo.setClassName(vo.getClassName());
			resultVo.setModifyBy(SysUserUtils.getSysUser().getUsername());
			resultVo.setModifyTime(new Date());
			resultVo.setExamRecord(Integer.valueOf(String.valueOf(map.get("examRecord"))));
			resultInfoVOS.add(resultVo);
		}
		boolean updateBatch = saveOrUpdateBatch(resultInfoVOS);
		if (updateBatch) {
			return 1;
		}
		return null;
	}
	
	private void updateExamInfo(ExamResultInfoVO vo) {
		ExamInfoVO infoVO = new ExamInfoVO();
		infoVO.setId(vo.getId());
		infoVO.setCourseId(Long.valueOf(vo.getCourseId()));
		infoVO.setCourseName(vo.getCourseName());
		infoVO.setExamName(vo.getExamName());
		infoVO.setClassId(vo.getClassId());
		infoVO.setExamBeginTime(vo.getExamBeginTime());
		infoVO.setExamEndTime(vo.getExamEndTime());
		infoVO.setInvigilationTeacher(vo.getInvigilationTeacher());
		infoVO.setExamRoom(vo.getExamRoom());
		infoVO.setModifyBy(SysUserUtils.getSysUser().getUsername());
		infoVO.setModifyTime(new Date());
		examInfoDao.updateById(infoVO);
	}
	
	private ExamInfoVO insertExamInfo(ExamResultInfoVO vo) {
		ExamInfoVO infoVO = buildExamInfo(vo);
		
		LambdaQueryWrapper<ExamInfoVO> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(ExamInfoVO::getExamName, vo.getExamName());
		queryWrapper.and((query) -> {
			query.eq(ExamInfoVO::getClassId, vo.getClassId());
			query.eq(ExamInfoVO::getCourseId, vo.getCourseId());
		});
		
		if (Objects.nonNull(examInfoDao.selectOne(queryWrapper))) {
			return null;
		}
		
		examInfoService.addOrUpdateExamInfo(infoVO);
		
		LambdaQueryWrapper<ExamInfoVO> examInfoQuery = new LambdaQueryWrapper<>();
		examInfoQuery.eq(ExamInfoVO::getExamName, vo.getExamName());
		examInfoQuery.and((query) -> {
			query.eq(ExamInfoVO::getClassId, vo.getClassId());
			query.eq(ExamInfoVO::getCourseId, vo.getCourseId());
		});
		return examInfoDao.selectOne(examInfoQuery);
	}
	
	@NotNull
	private ExamInfoVO buildExamInfo(ExamResultInfoVO vo) {
		ExamInfoVO infoVO = new ExamInfoVO();
		infoVO.setClassId(vo.getClassId());
		infoVO.setClassName(vo.getClassName());
		infoVO.setCourseId(Long.valueOf(vo.getCourseId()));
		infoVO.setCourseName(vo.getCourseName());
		infoVO.setExamName(vo.getExamName());
		infoVO.setExamBeginTime(vo.getExamBeginTime());
		infoVO.setExamEndTime(vo.getExamEndTime());
		infoVO.setExamRoom(vo.getExamRoom());
		infoVO.setInvigilationTeacher(vo.getInvigilationTeacher());
		infoVO.setCreateBy(SysUserUtils.getSysUser().getUsername());
		infoVO.setCreateTime(new Date());
		if (vo.getExamRecord() > 0) {
			infoVO.setPid(vo.getId());
		}
		return infoVO;
	}
	
	@Override
	public int deleteResultById(ExamResultInfoVO vo) {
		return this.baseMapper.deleteById(vo.getId());
	}
	
	@Override
	public int deleteBatchExamResult(List<ExamResultInfoVO> list) {
		int num = 0;
		for (ExamResultInfoVO vo : list) {
			this.baseMapper.deleteById(vo.getId());
			num++;
		}
		return num;
	}
	
	@Override
	public int addBatchExamResult(List<ExamResultInfoVO> list) {
		int num = 0;
		String username = SysUserUtils.getSysUser().getUsername();
		for (ExamResultInfoVO vo : list) {
			vo.setCreateBy(username);
			vo.setCreateTime(new Date());
			this.baseMapper.insert(vo);
			num++;
		}
		if (num == list.size()) return 1;
		return 0;
	}
	
	@Override
	public List<ExamInfoVO> queryExamByName(ExamInfoVO vo) {
		List<ExamInfoVO> infoPageList = examInfoDao.findExamInfoPageList(vo);
		Map<String, List<ExamInfoVO>> listMap = infoPageList.stream().collect(Collectors.groupingBy(ExamInfoVO::getExamName));
		
		// 重组数据
		List<ExamInfoVO> examInfoVOS = new ArrayList<>();
		for (Map.Entry<String, List<ExamInfoVO>> stringListEntry : listMap.entrySet()) {
			List<ExamInfoVO> value = stringListEntry.getValue();
			ExamInfoVO examInfoVO = value.get(0);
			List<Map<String, String>> classList = new ArrayList<>();
			for (ExamInfoVO infoVO : stringListEntry.getValue()) {
				if (Integer.parseInt(infoVO.getStatus()) != 1) {
					continue;
				}
				Map<String, String> classMap = new HashMap<>();
				classMap.put("classId", infoVO.getClassId());
				classMap.put("className", infoVO.getClassName());
				classMap.put("classTeacher", infoVO.getUserName());
				classList.add(classMap);
			}
			examInfoVO.setClassList(classList);
			examInfoVOS.add(examInfoVO);
		}
		return examInfoVOS;
	}
	
	@Override
	public List<BStudent> queryClassStudents(ExamInfoVO vo) {
		QueryWrapper<BStudent> wrapper = new QueryWrapper<>();
		wrapper.select("student_no", "student_name", "id", "class_id", "class_name");
		wrapper.eq("class_id", vo.getClassId());
		wrapper.eq("is_graduated","0");
		List<BStudent> list = bStudentDao.selectList(wrapper);
		return list;
	}
	
	@Override
	public List<ExamResultInfoVO> queryExamResultList(ExamResultInfoVO vo) {
		LambdaQueryWrapper<ExamResultInfoVO> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(ExamResultInfoVO::getExamId, vo.getExamId());
		wrapper.eq(ExamResultInfoVO::getExamRecord, vo.getExamRecord());
		wrapper.and((queryWrapper) -> {
			queryWrapper.eq(ExamResultInfoVO::getClassId, vo.getClassId());
		});
		return this.baseMapper.selectList(wrapper);
	}
	
	@Override
	public List<BStudent> queryMakeUpExam(ExamInfoVO vo) {
		List<BStudent> upExamResult = baseMapper.findMakeUpExamResult(vo);
		return upExamResult;
	}
	
	@Override
	public ExamInfoVO getExamDetailById(Map<String, String> params) {
		String examId = params.get("examId");
		String examRecord = params.get("examRecord");
		// 查询考试信息
		ExamInfoVO examInfoVO = examInfoDao.selectById(examId);
		
		// 查询已录入的学生名单
		LambdaQueryWrapper<ExamResultInfoVO> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(ExamResultInfoVO::getExamId, examId);
		if (!Objects.equals(examRecord, "0")) {
			// 查询上一次考试没有通过的学生名单
			examRecord = String.valueOf(Integer.parseInt(examRecord) - 1);
			queryWrapper.eq(ExamResultInfoVO::getIsPass, "0");
		}
		queryWrapper.eq(ExamResultInfoVO::getExamRecord, examRecord);
		List<ExamResultInfoVO> resultInfoVOS = this.baseMapper.selectList(queryWrapper);
		
		if (CollectionUtil.isEmpty(resultInfoVOS)) {
			resultInfoVOS = new ArrayList<>();
			examInfoVO.setClassName(null);
		} else {
			examInfoVO.setClassName(resultInfoVOS.get(0).getClassName());
			
		}
		examInfoVO.setExamStudents(resultInfoVOS);
		return examInfoVO;
	}
	
	@Override
	public List<BStudent> getExamStudentsByExamId(String examId) {
		List<BStudent> studentsByExamId = examResultInfoDao.getExamStudentsByExamId(examId);
		return studentsByExamId;
	}
	
	@Override
	public List<ExamResultInfoVO> getResitExamStudents(String examId) {
		LambdaQueryWrapper<ExamResultInfoVO> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(ExamResultInfoVO::getResitExamId, examId);
		List<ExamResultInfoVO> resultInfoVOS = examResultInfoDao.selectList(queryWrapper);
		return resultInfoVOS;
	}
}
